﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Text;
using System.Globalization;

using OpenGL;

namespace Exhibition
{
	partial class ExhibitionForm : GLForm
	{
		public void Run()
		{
			bool fullScreen = false;

			// Ask The User Which Screen Mode They Prefer
			if (true)
				fullScreen = false;
			else
			{
				if (MessageBox.Show("Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",
					MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
				{
					fullScreen = true;
				}
			}
			while (true)
			{
				CultureInfo I = Thread.CurrentThread.CurrentCulture.Clone() as CultureInfo;
				I.NumberFormat.NumberDecimalSeparator = ".";
				Thread.CurrentThread.CurrentCulture = I;
				Thread.CurrentThread.CurrentUICulture = I;

				FullScreen = fullScreen;					// set the user display property option

				if (!SetupRenderingContext())				// setup form and OpenGL
				{
					break;										// initialization failed, quit
				}

				Application.Run(this);
				if (Done)									// Was There A Quit Received?
				{
					break;
				}
				fullScreen = FullScreen;					// switching between full screen and windowed, persist full screen option between forms
			}
		}

		enum ProgramPhase
		{
			FirstFrame,
			Initializing,
			Running
		}
		enum SelectMode : int
		{
			Camera = 0,
			Carpet = 1,
			FirstRoom = 2
		}
		ProgramPhase PrgPhase = ProgramPhase.FirstFrame;
		//ExhibPhase EPhase = ExhibPhase.Standing;

		new ExhibitionBase Site = new ExhibitionBase();
		List<Carpet> Carpets = new List<Carpet>();

		List<double> Widths = new List<double>();
		List<double> Heights = new List<double>();

		public ExhibitionForm()
			: base()
		{
			this.Text = "Kiállítás bemutató";
			Icon = Exhibition.Properties.Resources.Museum_icon;
			Widths.Clear();
			Heights.Clear();
			String[] Buf = File.ReadAllLines("data.txt");
			foreach (String S in Buf)
			{
				if (S != "" && S[0] == 'C')
				{
					Widths.Add(double.Parse(S.Split('\t')[3]) / 100);
					Heights.Add(double.Parse(S.Split('\t')[2]) / 100);
				}
			}
			WindowState = FormWindowState.Maximized;
			MaximizeBox = false;
		}

		void LoadData()
		{
			Camera = new GLWalkCamera();
			Carpets.Clear();

			String[] Buf = File.ReadAllLines("data.txt", Encoding.UTF8);
			for (int i = 0; i < Buf.Length; i++)
			{
				String[] Row = Buf[i].Split('\t');
				switch (Row[0])
				{
					case "S":
						{
							V3D pos = new V3D(double.Parse(Row[1]), double.Parse(Row[2]), double.Parse(Row[3]));
							//V3D dir = new V3D(double.Parse(Row[4]), double.Parse(Row[5]), double.Parse(Row[6]));
							V3D dir = new V3D(double.Parse(Row[4]), 0, double.Parse(Row[6])).Unit + V3D.Green * 0.1;
							Camera.AddStatic(pos, dir);
						}
						break;
					case "C":
						{
							int CarpetID = int.Parse(Row[1]);
							int W = int.Parse(Row[3]);
							int H = int.Parse(Row[2]);
							int WallID = int.Parse(Row[4]);
							bool BackSide = int.Parse(Row[5]) == 1;
							double WallX = double.Parse(Row[6]);

							Carpet C = new Carpet((CarpetID + 1).ToString("00") + ".jpg", W, H, Site.Walls[WallID], BackSide, WallX, CarpetID + 1, Row[7]);
							Carpets.Add(C);

							Camera.AddCarpet(C);
						}
						break;
					case "T":
						{
							Bitmap B = new Bitmap(int.Parse(Row[4]) * 10, int.Parse(Row[5]) * 10);
							Graphics G = Graphics.FromImage(B);
							Image I = Image.FromFile("bg.jpg");
							G.DrawImage(I, new Rectangle(0, 0, B.Width, B.Height), new Rectangle(0, 0, I.Width, I.Height), GraphicsUnit.Pixel);
							StringFormat SF = StringFormat.GenericDefault;
							SF.Alignment = StringAlignment.Center;
							SF.Trimming = StringTrimming.Word;
							
							G.DrawString(Row[6].Replace("_", "\n\n"), new Font("Augusta", 108), Brushes.Black, new RectangleF(0, 50, B.Width, 500), SF);
							G.DrawString(Row[7].Replace("_", "\n\n"), new Font("Arial", 72), Brushes.Black, new RectangleF(50, 350, B.Width-100, B.Height - 100));
							G.Flush();
							G.Dispose();
							I.Dispose();
							Carpet C = new Carpet(B, B.Width / 10.0, B.Height / 10.0, Site.Walls[int.Parse(Row[1])], int.Parse(Row[2]) == 1, double.Parse(Row[3]), -0, "");
							if (i < 25)
								Carpets.Add(C);
							Camera.AddText(C);
							B.Dispose();
						}
						break;
					default:
						break;
				}
			}
			PrgPhase = ProgramPhase.Running;
		}
		void SaveData()
		{
			TextWriter W = File.CreateText("data2.txt");
			for (int i = 0; i < Camera.Stages.Count; i++)
				W.WriteLine(Camera.Stages[i].ToString());
			W.Close();
		}
		bool DevMode = true;
		bool debug = false;

		SelectMode selectmode = SelectMode.Camera;
		protected override void ProcessGLKey(Keys K, bool shift, bool control)
		{
			#region DevMode
			if (DevMode)
			{
				switch (K)
				{
					case Keys.S:
						if (control)
							SaveData();
						break;
					case Keys.L:
						if (control)
							LoadData();
						break;
					case Keys.Up:
						if (selectmode == SelectMode.Camera)
						{
							ItemSel = (ItemSel + 2) % (Camera.Stages.Count + 1) - 1;
							Camera.currentindex = ItemSel;
							if (ItemSel > -1)
								Camera.currentstage = Camera.Stages[ItemSel];
						}
						else if (selectmode == SelectMode.Carpet)
							ItemSel = (ItemSel + 2) % 25 - 1;
						break;
					case Keys.Down:
						if (selectmode == SelectMode.Camera)
						{
							ItemSel = (ItemSel + Camera.Stages.Count + 1) % (Camera.Stages.Count + 1) - 1;
							Camera.currentindex = ItemSel;
							if (ItemSel > -1)
								Camera.currentstage = Camera.Stages[ItemSel];
						}
						else if (selectmode == SelectMode.Carpet)
							ItemSel = (ItemSel + 25) % 25 - 1;
						break;
				}
				if (K == Keys.D)
				{
					debug ^= true;
				}
				else if (K == Keys.Tab)
				{
					selectmode = (SelectMode)((((int)selectmode) + 1) % 3);
					ItemSel = -1;
				}
				else
					if (selectmode == SelectMode.Carpet)
					{
						switch (K)
						{
							case Keys.L:
								if (ItemSel > -1)
									Carpets[ItemSel].WallX += control ? 0.1 : 1;
								break;
							case Keys.J:
								if (ItemSel > -1)
									Carpets[ItemSel].WallX -= control ? 0.1 : 1;
								break;
							default:
								break;
						}
					}
					else if (selectmode == SelectMode.Camera)
					{
						switch (K)
						{
							case Keys.NumPad8:
								if (ItemSel > -1)
									Camera.currentstage.Position += Camera.currentstage.Target.Unit * (control ? 0.5 : 0.1);
								break;
							case Keys.NumPad2:
								if (ItemSel > -1)
									Camera.currentstage.Position -= Camera.currentstage.Target.Unit * (control ? 0.5 : 0.1);
								break;
							case Keys.NumPad4:
								if (ItemSel > -1)
									Camera.currentstage.Position += Camera.currentstage.Target.Unit.RotY(90) * (control ? 0.5 : 0.1);
								break;
							case Keys.NumPad6:
								if (ItemSel > -1)
									Camera.currentstage.Position -= Camera.currentstage.Target.Unit.RotY(90) * (control ? 0.5 : 0.1);
								break;
							case Keys.NumPad7:
								if (ItemSel > -1)
									Camera.currentstage.Target.DoRot(V3D.Green, control ? 15 : 3);
								break;
							case Keys.NumPad9:
								if (ItemSel > -1)
									Camera.currentstage.Target.DoRot(-V3D.Green, control ? 15 : 3);
								break;
							default:
								break;
						}
					}
			}
			#endregion
			switch (K)
			{
				case Keys.Right:
					ItemSel=Camera.MoveForward(1);
					break;
				case Keys.Left:
					ItemSel=Camera.MoveBackward(1);
					break;
				case Keys.C:
					ShowCam ^= true;
					break;
				case Keys.T:
					Site.WallTXT.Reload();
					break;
				default:
					break;
			}
		}

		protected override void Process(double dt, double tt)
		{
			switch (PrgPhase)
			{
				case ProgramPhase.FirstFrame:
					PrgPhase = ProgramPhase.Initializing;
					break;
				case ProgramPhase.Initializing:
					break;
				case ProgramPhase.Running:
					Camera.Process(dt);
					break;
				default:
					break;
			}
		}

		int ItemSel = -1;
		void DrawCarpets()
		{
			foreach (Carpet C in Carpets)
				C.Draw(selectmode == SelectMode.Carpet && ItemSel == C.Legend - 1);

			foreach (Carpet C in FirstRoomElements)
				C.Draw(selectmode == SelectMode.Carpet && ItemSel == C.Legend - 1);
		}

		protected override bool DrawGLScene()
		{
			GL.glClearColor(0.8f, 0.8f, 0.8f, 1);
			GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
			GL.glLoadIdentity();									// Reset The Current Modelview Matrix
			switch (PrgPhase)
			{
				case ProgramPhase.FirstFrame:
					GL.gluLookAt(0, 0, 3, 0, 0, 0, 0, 1, 0);
					Text = "Loading...";
					break;
				case ProgramPhase.Initializing:
					//DrawLoader();
					break;
				case ProgramPhase.Running:
					//Text = "Running";
					DrawExhibition();
					break;
				default:
					break;
			}
			return true;										// Keep Going
		}

		GLText T;
		GLText Image_Title;
		GLTexture Door;

		List<Carpet> FirstRoomElements = new List<Carpet>();
		List<Carpet> Texts = new List<Carpet>();

		protected override void InitGL()
		{
			Door = new GLTexture("door.jpg");
			GL.glEnable(GL.GL_CULL_FACE);
			GL.glCullFace(GL.GL_FRONT);
			T = new GLText("Times New Roman");
			Image_Title = new GLText("Augusta");
			Site.BuildRoom(Widths, Heights);
			LoadData();
			InitCamera();

			{
				String TEXT_TITLE = "Flandria kincsei";
				String TEXT_TITLE2 = "Ipolyi Arnold falikárpit-gyűjteménye";
				String TEXT_CIT = "„Őrizzük emlékeinket, gyűjtsük össze_töredékeinket, nehogy végleg elvesszenek,_s ez által is üresebb legyen a múlt,_szegényebb a jelen, s kétesebb a jövő.”";
				Bitmap B = new Bitmap(2000, 1000);
				Graphics G = Graphics.FromImage(B);
				G.DrawImage(Image.FromFile("bg.jpg"), new Rectangle(0, 0, B.Width, B.Height));
				G.DrawImage(Image.FromFile("P.jpg"), 50, 50);
				StringFormat SF = StringFormat.GenericDefault;
				SF.LineAlignment = StringAlignment.Near;
				SF.Alignment = StringAlignment.Far;
				G.DrawString(TEXT_TITLE, new Font("Augusta", 144), Brushes.Black, 350, 30);
				G.DrawString(TEXT_TITLE2, new Font("Augusta", 72), Brushes.Black, 360, 200);
				G.DrawString(TEXT_CIT.Replace("_", "\n"), new Font("Arial", 48, FontStyle.Italic), Brushes.Black, new PointF(1950, 420), SF);
				G.DrawString("/Ipolyi Arnold/", new Font("Arial", 48, FontStyle.Italic), Brushes.Black, 1500, 770);
				G.DrawString("A kiállítás megtekinthető: 2014. április 1. – 2014. szeptember 30.", new Font("Arial", 36), Brushes.Black, 50, 900);
				G.Flush();
				G.Dispose();
				FirstRoomElements.Add(new Carpet(B, B.Width / 5, B.Height / 5, Site.Walls[11], false, 2.5, -1, ""));

				FirstRoomElements.Add(new Carpet("C1.jpg", 76 * 2.5, 86 * 2.5, Site.Walls[1], false, 1.2, -1, ""));
				FirstRoomElements.Add(new Carpet("C2.jpg", 65 * 3, 62 * 3, Site.Walls[1], false, 3.4, -1, ""));
				FirstRoomElements.Add(new Carpet("C3.jpg", 73 * 3, 44 * 3, Site.Walls[2], false, 19.2, -1, ""));
				FirstRoomElements.Add(new Carpet("C4.jpg", 82 * 3, 62 * 3, Site.Walls[2], false, 16.5, -1, ""));
				FirstRoomElements.Add(new Carpet("C5.jpg", 61 * 4, 41 * 4, Site.Walls[10], true, 5, -1, ""));
				FirstRoomElements.Add(new Carpet("C6.jpg", 98 * 3, 82 * 3, Site.Walls[10], true, 2, -1, ""));
			}

			double[] PX = new double[] { 12.7, 1.3, 11.0, 9.0, 7.2, 5.4 };
			double[] PS = new double[] { 1, 2, 1, 1, 1, 1 };
			for (int i = 1; i <= 6; i++)
			{
				MemoryStream MS = new MemoryStream(File.ReadAllBytes("P" + i.ToString("00") + ".jpg"));
				Bitmap B = (Bitmap)Bitmap.FromStream(MS);
				MS.Dispose();
				double S = 120 * PS[i - 1] / B.Height;

				Wall W = i == 2 ? Site.Walls[5] : Site.Walls[1];

				Carpet C = new Carpet(B, B.Width * S, B.Height * S, W, i == 2, PX[i - 1], -1, "");
				Console.WriteLine(B.Size);
				FirstRoomElements.Add(C);
			}
			//Texts.Add(new Carpet("text1.jpg", 100, 100, Site.Walls[8], true, 0.5, -1, ""));

			GenerateIntro();
			GenerateFirstroom();
		}
		void GenerateIntro()
		{
		}
		void GenerateFirstroom()
		{
		}

		void InitCamera()	
		{
			/*Camera = new GLWalkCamera(new V3D(Site.TOTAL_LENGTH / 2 - 1.5, 1.5, 4), new V3D(0, 0, -1), new V3D(0, 0, 0));
			//Camera = new GLWalkCamera(new V3D(0,10,10), new V3D(0, 0, 1), new V3D(0, 0, -1));
			Camera.AddToPath(new V3D(Site.TOTAL_WIDTH / 2 - 1.5, 1.5, -1), new V3D(0, 0, 0), new V3D(-1, 0, 0), 0.6, -1);
			Camera.AddToPath(new V3D(Site.TOTAL_WIDTH / 2 - 4.5, 1.5, -1), new V3D(0, 0, 0), new V3D(0, 0, 1), 0.6, -1);
		*/
		}
		GLWalkCamera Camera;
		bool ShowCam = false;
		void SetCamera()
		{
			GL.glLoadIdentity();
			if (ShowCam)
				Camera.SetView();
			else
				GL.gluLookAt(0, 13, 0, 0, 0, 0, 0, 0, -1);
				//gluLookAt(9, 2, 0, 9, 2, 10, 0, 1, 0);
		}
		void DrawExhibition()
		{
			SetCamera();
			DrawRoom();
			GL.glDisable(GL.GL_CULL_FACE);
			GL.glPushMatrix();
			GL.glTranslated(Site.TOTAL_LENGTH / 2 - Site.Walls[5].Length - 1, 1.5, Site.TOTAL_WIDTH / 2);
			GL.glRotated(180, 0, 1, 0);
			Door.Draw(2, 3, 1, 1);
			GL.glPopMatrix();
			GL.glPushMatrix();
			GL.glTranslated(-Site.TOTAL_LENGTH / 2 + Site.Walls[3].Length + 1, 1.5, -Site.TOTAL_WIDTH / 2);
			Door.Draw(2, 3, 1, 1);
			GL.glPopMatrix();
			GL.glEnable(GL.GL_CULL_FACE);
			if (debug)
			{
				for (int i = 0; i < Camera.Stages.Count; i++)
				{
					GL.glCol3D(ItemSel == i ? V3D.Green : V3D.Red);
					GL.glPushMatrix();
					GL.glTrans3D(Camera.Stages[i].Position);
					GL.DrawSign();
					GL.glCol3D(V3D.Yellow);
					GL.glLineWidth(3);
					GL.glBegin(GL.GL_LINES);
					GL.glV3D(V3D.Black);
					GL.glV3D(Camera.Stages[i].Target);
					GL.glEnd();
					GL.glLineWidth(1);
					GL.glPopMatrix();
					GL.glCol3D(V3D.White);
					if (i > 0)
					{
						GL.glBegin(GL.GL_LINES);
						GL.glV3D(Camera.Stages[i - 1].Position);
						GL.glV3D(Camera.Stages[i].Position);
						GL.glEnd();
					}
				}
			}
			GL.glEnable(GL.GL_TEXTURE_2D);
			GL.glEnable(GL.GL_COLOR_MATERIAL);

			GL.glEnable(GL.GL_LIGHTING);
			DrawCarpets();
		

			String DebugText = "Camera: " + Camera.Phase.ToString()
				+ "|Fade: " + Camera.prg.ToString("0.00")
				+ "|Stage: " + Camera.currentindex
				+ "|Stage phase: " + Camera.currentstage.Phase
				+ "|Selection: " + ItemSel.ToString("00");

			MakeOrtho();
			if (Camera.currentstage is CameraStage_Carpet)
			{
				CameraStage_Carpet C = Camera.currentstage as CameraStage_Carpet;
				GL.BlendAlpha2();
				GL.glBegin(GL.GL_QUADS);
				GL.glColor4d(0, 0, 0, Camera.currentstage.fade * 0.9);
				GL.glV3D(V3D.Black);
				GL.glV3D(V3D.Red * Width);
				GL.glV3D(V3D.Red * Width + V3D.Green * Height);
				GL.glV3D(V3D.Green * Height);
				GL.glEnd();
				GL.BlendOff();

				GL.glCol3D(V3D.White);
				if (Camera.currentstage.Phase == CameraStagePhase.Still)
				{
					GL.glDisable(GL.GL_DEPTH_TEST);
					GL.glPushMatrix();
					double w, h;

					if (Camera.currentstage is CameraStage_Text)
						Algebra3D.Resize(C.Carpetobj.Width, C.Carpetobj.Height, Width, Height, out w, out h);
					else
						Algebra3D.Resize(C.Carpetobj.Width, C.Carpetobj.Height, Width / 2, Height, out w, out h);

					GL.glTranslated(Camera.currentstage is CameraStage_Text ? Width / 2 : Width / 4, Height / 2, 0);
					GL.glRotated(180, 1, 0, 0);
					C.Carpetobj.T.Draw(w, h, 1, 1);
					GL.glPopMatrix();
					GL.glEnable(GL.GL_DEPTH_TEST);

					GL.BlendAlpha();
					if (!(Camera.currentstage is CameraStage_Text))
					{
						String[] CarpetText = C.Carpetobj.Text.Split('|');
						Image_Title.DrawString(CarpetText[0].Replace('_', '|'), Width * 3 / 4, 10, 48, 30, StringAlignment.Center);
						for (int i = 1; i < CarpetText.Length; i++)
							T.DrawText(CarpetText[i], Width / 2 + 30, 150 + i * 24, 24, 15, StringAlignment.Near);
					}
				}
				DebugText += "\nText: " + C.Carpetobj.Text;
			}
			int N = Camera.Stages.IndexOf(Camera.currentstage);
			//T.DrawString(N == -1 ? "--" : N.ToString("00"), 0, 20, 32, 32, StringAlignment.Near);

			GL.BlendOff();
			GL.glColor3d(1, 1, 1);
			MakePerpective(90);
		}

		void DrawRoom()
		{
			Site.Draw();
			//if (debug)
			//	Camera.DrawPath(carpetmode ? -1 : ItemSel);
		}
	}
}